from django import forms
from django.contrib.auth import get_user_model, forms as auth_forms
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.core import validators
from django.contrib.auth import authenticate
from django.contrib.auth.forms import PasswordChangeForm

from captcha.fields import CaptchaField

from .crypto import decrypt

UserModel = get_user_model()


class PasswordField(forms.CharField):

    def __init__(self, *args, **kwargs):
        render_value = kwargs.pop('render_value', False)
        kwargs['widget'] = forms.PasswordInput(render_value=render_value,
                                               attrs={'placeholder':
                                                          kwargs.get("label")})
        super().__init__(*args, **kwargs)


class LoginForm(forms.Form):
    user = None
    error_messages = {
        'account_inactive':
            _("This account is currently inactive."),

        'email_password_mismatch':
            _("邮箱或密码不正确"),

        'username_password_mismatch':
            "用户名或密码不正确.",
    }

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super().__init__(*args, **kwargs)
        self.fields['login'] = forms.CharField(label="用户", widget=forms.TextInput(
            attrs={'autofocus': True, "placeholder": "用户名/邮箱"}))
        self.fields['password'] = PasswordField(label='密码')
        self.fields['remember'] = forms.BooleanField(label="记住我", required=False)

    def user_credentials(self):
        credentials = {}
        login = self.cleaned_data['login']
        if self._is_login_email(login):
            credentials["email"] = login
        credentials["username"] = login
        credentials["password"] = self.cleaned_data["password"]
        return credentials

    def _is_login_email(self, login):
        try:
            validators.validate_email(login)
            ret = True
        except ValidationError:
            ret = False
        return ret

    def clean_password(self):
        password = self.cleaned_data["password"]
        pwd = decrypt(password)
        return pwd

    def clean(self):
        cleaned_data = super(LoginForm, self).clean()
        if self._errors:
            return
        credentials = self.user_credentials()
        user = authenticate(self.request, **credentials)
        if user:
            self.user = user
        else:
            login = cleaned_data['login']
            if self._is_login_email(login):
                auth_method = 'email'
            else:
                auth_method = 'username'
            raise forms.ValidationError(self.error_messages[f'{auth_method}_password_mismatch'])
        return cleaned_data


class LoginCaptchaForm(LoginForm):
    captcha = CaptchaField(error_messages={"invalid": "验证码错误"})


class UserPasswordChangeForm(PasswordChangeForm):
    def clean_old_password(self):
        old_password = self.cleaned_data["old_password"]
        self.cleaned_data["old_password"] = decrypt(old_password)
        return super().clean_old_password()

    def clean_new_password1(self):
        return decrypt(self.cleaned_data["new_password1"])

    def clean_new_password2(self):
        self.cleaned_data["new_password2"] = decrypt(self.cleaned_data["new_password2"])
        return super().clean_new_password2()


class UserChangeForm(auth_forms.UserChangeForm):
    class Meta(auth_forms.UserChangeForm.Meta):
        model = UserModel


class UserCreationForm(auth_forms.UserCreationForm):
    error_message = auth_forms.UserCreationForm.error_messages.update(
        {"duplicate_username": _("This username has already been taken.")}
    )

    class Meta(auth_forms.UserCreationForm.Meta):
        model = UserModel

    def clean_username(self):
        username = self.cleaned_data["username"]

        try:
            UserModel.objects.get(username=username)
        except UserModel.DoesNotExist:
            return username

        raise ValidationError(self.error_messages["duplicate_username"])
